<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="运行时反射">
<meta name="twitter:description" content="<p>反射：反射定律；Value：获取原始类型，修改反射的值，获取底层类型（Kind），Elem方法；Type：反射判断是否实现了接口；使用反射：反射遍历结构体的字段和方法，获取修改字段，获取调用方法。</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/gotour-reflection.html"/>
<meta property="og:title" content="来玩魔王的咚 | 运行时反射" />
<meta property="og:description" content="<p>反射：反射定律；Value：获取原始类型，修改反射的值，获取底层类型（Kind），Elem方法；Type：反射判断是否实现了接口；使用反射：反射遍历结构体的字段和方法，获取修改字段，获取调用方法。</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>反射：反射定律；Value：获取原始类型，修改反射的值，获取底层类型（Kind），Elem方法；Type：反射判断是否实现了接口；使用反射：反射遍历结构体的字段和方法，获取修改字段，获取调用方法。</p>" />

    <meta name="tags" content="gotour" />
    <meta name="tags" content="反射" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li class="active"><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-12-17 10:00:00+08:00">
                <script>document.write(moment('2020-12-17 10:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-12-17 10:00:00+08:00">
                <script>document.write(moment('2020-12-18 10:30:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            运行时反射
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#fan-she">反射</a><ul>
<li><a href="#reflecttype-he-reflectvalue">reflect.Type 和 reflect.Value</a></li>
<li><a href="#fan-she-ding-lv">反射定律</a></li>
</ul>
</li>
<li><a href="#value">Value</a><ul>
<li><a href="#huo-qu-yuan-shi-lei-xing">获取原始类型</a></li>
<li><a href="#xiu-gai-dui-ying-de-zhi">修改对应的值</a></li>
<li><a href="#huo-qu-di-ceng-lei-xing-kind">获取底层类型（Kind）</a></li>
<li><a href="#elem-fang-fa">Elem 方法</a></li>
</ul>
</li>
<li><a href="#type">Type</a><ul>
<li><a href="#shi-fou-shi-xian-le-mou-jie-kou">是否实现了某接口</a></li>
</ul>
</li>
<li><a href="#shi-yong-fan-she">使用反射</a><ul>
<li><a href="#bian-li-zi-duan">遍历字段</a></li>
<li><a href="#bian-li-fang-fa">遍历方法</a></li>
<li><a href="#huo-qu-zi-duan">获取字段</a></li>
<li><a href="#huo-qu-fang-fa">获取方法</a></li>
<li><a href="#diao-yong-fang-fa">调用方法</a></li>
</ul>
</li>
</ul>
</div>
<p>这篇相对比较简单，目的是讲明白反射能做什么，是怎么用的。搞明白之后，再去看下面两篇参考下代码怎么组织，解决实际的问题：</p>
<ul>
<li><a href="/gopl-reflection-1.html">gopl反射1</a></li>
<li><a href="/gopl-reflection-2.html">gopl反射2</a></li>
</ul>
<h3 id="fan-she"><a class="toclink" href="#fan-she">反射</a></h3>
<p>反射提供了一种可以在运行时操作任意类型对象的能力。比如查看一个接口变量的具体类型、查看一个结构体有多少字段、修改某个字段的值，等等。<br>
有的函数接收空接口作为参数，参数可以是任意类型。这种情况下，如果想知道传递的具体类型，就需要使用反射。如果是结构体，想知道有哪些字段和方法，也需要反射。  </p>
<h4 id="reflecttype-he-reflectvalue"><a class="toclink" href="#reflecttype-he-reflectvalue">reflect.Type 和 reflect.Value</a></h4>
<p>反射功能由reflect包提供，它定义了两个重要的类型：</p>
<ul>
<li>reflect.Value: 对应的是变量的值。如果你需要进行和变量的值有关的操作，应该优先使用reflect.Value。比如获取变量的值、修改变量的值等。  </li>
<li>reflect.Type: 对应的是变量的类型。如果你需要进行和变量的类型本身有关的操作，应该优先使用reflect、.Type。比如获取结构体内的字段、类型拥有的方法集等。  </li>
</ul>
<p>任何接口都由两部分组成：接口的具体类型（Type），以及具体类型对应的值（Value）。<br>
标准库提供了reflect.Type表示变量的类型，并提供了reflect.TypeOf函数返回动态类型。<br>
标准库提供了reflect.Value表示变量的值，并提供了reflect.ValueOf函数返回动态值。<br>
参考示例：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">showTpyeValue</span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">it</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">iv</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">it</span><span class="p">,</span><span class="w"> </span><span class="nx">iv</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w">  </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">showTpyeValue</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w">     </span><span class="c1">// int 1</span><span class="w"></span>
<span class="w">    </span><span class="nx">showTpyeValue</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)</span><span class="w">   </span><span class="c1">// float64 2</span><span class="w"></span>
<span class="w">    </span><span class="nx">showTpyeValue</span><span class="p">(</span><span class="s">&quot;abc&quot;</span><span class="p">)</span><span class="w"> </span><span class="c1">// string abc</span><span class="w"></span>
<span class="w">    </span><span class="nx">showTpyeValue</span><span class="p">(</span><span class="sc">&#39;A&#39;</span><span class="p">)</span><span class="w">   </span><span class="c1">// int32 65</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>函数reflect.TypeOf和reflect.ValueOf，接收的都是空接口。分别返回reflect.Type和reflect.Value的值。  </p>
<h4 id="fan-she-ding-lv"><a class="toclink" href="#fan-she-ding-lv">反射定律</a></h4>
<p>反射是计算机语言中程序检视其自身结构的一种方法，属于元编程的一种形式。反射灵活、强大，但也存在不安全。它可以绕过编译器的很多静态检查，滥用会造成混乱。为了帮助开发者更好地理解返回，Go语言的作者在博客上总结了反射的三大定律。<br>
一、任何的接口值interface{}都可以反射出反射对象，也就是reflect.Value和reflect.Type。通过函数reflect.ValueOf和reflect.TypeOf获得。<br>
二、反射对象也可以还原为interface{}变量，也就是第一条定律的可逆性，通过reflect.Value结构体的Interface方法获得。<br>
三、要修改反射的对象，该值必须可设置，也就是可寻址。  </p>
<p>这篇，先依次对这3条来展开讲解。第一条在上一小节。  </p>
<h3 id="value"><a class="toclink" href="#value">Value</a></h3>
<p>reflect.Value是一个结构体类型，可以包含一个任意类型的值。<br>
reflect.ValueOf函数接受interface{}参数，将接口的动态值以reflect.Value的形式返回。  </p>
<p>这是一个结构体类型，定义如下：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">Value</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">typ</span><span class="w"> </span><span class="o">*</span><span class="nx">rtype</span><span class="w"></span>
<span class="w">    </span><span class="nx">ptr</span><span class="w"> </span><span class="nx">unsafe</span><span class="p">.</span><span class="nx">Pointer</span><span class="w"></span>
<span class="w">    </span><span class="nx">flag</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>所有的字段都是不可导出的，所以只能使用reflect.Value的方法。方法有很多，主要就三类：</p>
<ol>
<li>用于获取和修改对应的值</li>
<li>和结构体字段有关，用于获取对应的字段</li>
<li>和类型上的方法集有关，用于获取对应的方法</li>
</ol>
<h4 id="huo-qu-yuan-shi-lei-xing"><a class="toclink" href="#huo-qu-yuan-shi-lei-xing">获取原始类型</a></h4>
<p>对应<strong>反射定律</strong>第二条。把reflect.Value类型再转回具体的类型。<br>
之前用reflect.ValueOf函数获取到了reflect.Value类型的值，也可以再调用结构体的Interface方法转回去：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%T: %[1]v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">)</span><span class="w">   </span><span class="c1">// int: 3</span><span class="w"></span>
<span class="w">    </span><span class="nx">iv</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%T: %[1]v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">iv</span><span class="p">)</span><span class="w">  </span><span class="c1">// reflect.Value: 3</span><span class="w"></span>
<span class="w">    </span><span class="nx">i2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">iv</span><span class="p">.</span><span class="nx">Interface</span><span class="p">().(</span><span class="kt">int</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%T: %[1]v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">i2</span><span class="p">)</span><span class="w">  </span><span class="c1">// int: 3</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这个就是reflect.Value类型和具体类型的互转。  </p>
<h4 id="xiu-gai-dui-ying-de-zhi"><a class="toclink" href="#xiu-gai-dui-ying-de-zhi">修改对应的值</a></h4>
<p>对应<strong>反射定律</strong>第三条。<br>
通过反射获取到接口的动态值，然后调用对应的方法设置值：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">changeValue</span><span class="p">(</span><span class="nx">ip</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">ip</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">SetInt</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
<span class="w">    </span><span class="nx">changeValue</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>首先，原地修改要传指针。<br>
然后，因为传入的是指针，修改需要操作指针指向的值。这要调用Elem方法来找到指针指向的值。<br>
最后，调用SetInt方法来设置一个int类型的值。<em>如果是其他类型，则还有其他对应的方法。</em>  </p>
<p>如果是结构体，还需要调用Field方法获取到字段，之后再进行修改：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">person</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Age</span><span class="w">  </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">chuangStruct</span><span class="p">(</span><span class="nx">ip</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">ip</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">Field</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">SetString</span><span class="p">(</span><span class="s">&quot;Jerry&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">Field</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">SetInt</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">p</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">person</span><span class="p">{</span><span class="s">&quot;Tom&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span><span class="w">   </span><span class="c1">// {Tom 18}</span><span class="w"></span>
<span class="w">    </span><span class="nx">chuangStruct</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">p</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span><span class="w">   </span><span class="c1">// {Jerry 16}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这里还有个问题没解决，虽然定义的函数接收的是空接口，但是这里的代码明确知道要传入的数据的类型。这里缺少对类型的判断。<br>
在实际应用中，使用空接口的时候，接收的值可以是任意类型，需要先判断类型，然后再执行对应的操作。具体看下一节。  </p>
<h4 id="huo-qu-di-ceng-lei-xing-kind"><a class="toclink" href="#huo-qu-di-ceng-lei-xing-kind">获取底层类型（Kind）</a></h4>
<p>对应<strong>反射定律</strong>第三条。补充一个类型的判断。<br>
这里的底层类型主要就是指基础类型。实际类型可以是各种名称，但是底层类型或者说基础类型就那么几种。如果要对实际类型判断，那么会有无数种可能。如果只是判断底层类型，就只有有限的那些。并且相同的底层类型中存储的值实际也是一样的。<br>
用reflec.Value的Kind方法可以区分不同的类型。尽管有无限种类型，但类型的<strong>分类</strong>（kind）只有少数几种。<br>
下面的例子中定义了一个自定义类型。先用reflect.TypeOf获取到动态类型，这是自己定义的类型名称。之后又用Kind方法获取到底层类型：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">age</span><span class="w"> </span><span class="kt">uint</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">age</span><span class="p">(</span><span class="mi">18</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">a</span><span class="p">))</span><span class="w">          </span><span class="c1">// main.age</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">a</span><span class="p">).</span><span class="nx">Kind</span><span class="p">())</span><span class="w">  </span><span class="c1">// uint</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">a</span><span class="p">).</span><span class="nx">Kind</span><span class="p">())</span><span class="w">   </span><span class="c1">// uint</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>下面的示例，可以判断3中类型，然后分别调用指定的方法：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">changeValue</span><span class="p">(</span><span class="nx">ip</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">ipv</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">ip</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">switch</span><span class="w"> </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Int</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">SetInt</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">String</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">SetString</span><span class="p">(</span><span class="s">&quot;jerry&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Bool</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="nx">ipv</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">SetBool</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
<span class="w">    </span><span class="nx">changeValue</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;Tom&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">changeValue</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">b</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kc">true</span><span class="w"></span>
<span class="w">    </span><span class="nx">changeValue</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">b</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">b</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>因为要修改值，要传指针，无论是获取底层类型还是设置值，都要先的调用Elem()方法，获取指针指向的值。如果漏了Elem()方法，Kind()方法会获取到指针类型（ptr）。  </p>
<h4 id="elem-fang-fa"><a class="toclink" href="#elem-fang-fa">Elem 方法</a></h4>
<p>这个方法如果概念不清楚，容易让人迷惑。具体用法上面已经演示过了，就是取到指针指向的值。但是还要单独说几句。<br>
这个方法是把一个指针的reflect.Value类型转为指向的值的reflect.Value类型。转换前后类型一样，因此可以链式调用，用起来很方便。但也会让人迷惑，什么时候需要加上Elem方法转一下，什么时候不需要。<br>
当reflect.Value对应的是指针类型的时候，就有可能需要用到这个方法。比如，修改值的时候，需要传指针才能修改，但是进行修改操作的时候需要对值进行操作。<br>
有时候需要对指针调用方法，有时候需要对指针指向的值调用方法。用错的时候，有时候会获得错误的结果。比如结构体的方法，指针接收者包含所有的方法，这时候需要传入指针来检查。但如果用Elem方法转为值，再去反射值的方法，就不包含指针接收者的方法了。<br>
更多的时候，会在运行时引发Panic。<em>Elem方法前后的类型是一样的，编译器的类型检查是发现不了问题的。</em>  </p>
<h3 id="type"><a class="toclink" href="#type">Type</a></h3>
<p>reflect.Type是一个接口，每个Type表示Go语言的一个类型。<br>
reflect.TypeOf函数接受interface{}参数，以reflect.Type的形式返回动态类型。  </p>
<p>这是一个接口类型，定义的方法比较多，下面列出部分常用的：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">Type</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Implements</span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">Type</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="w">    </span><span class="nx">AssignableTo</span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">Type</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="w">    </span><span class="nx">ConvertibleTo</span><span class="p">(</span><span class="nx">u</span><span class="w"> </span><span class="nx">Type</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>
<span class="w">    </span><span class="nx">Comparable</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span><span class="w"></span>

<span class="w">    </span><span class="c1">// 一下方法和Value结构体的功能相同</span><span class="w"></span>
<span class="w">    </span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="nx">Kind</span><span class="w"></span>

<span class="w">    </span><span class="nx">Method</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">Method</span><span class="w"></span>
<span class="w">    </span><span class="nx">MethodByName</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">Method</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">NumMethod</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">Elem</span><span class="p">()</span><span class="w"> </span><span class="nx">Type</span><span class="w"></span>
<span class="w">    </span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">StructField</span><span class="w"></span>
<span class="w">    </span><span class="nx">FieldByIndex</span><span class="p">(</span><span class="nx">index</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">StructField</span><span class="w"></span>
<span class="w">    </span><span class="nx">FieldByName</span><span class="p">(</span><span class="nx">name</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">StructField</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">FieldByNameFunc</span><span class="p">(</span><span class="nx">match</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">StructField</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">NumField</span><span class="p">()</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>Implements(u Type)方法：用于判断是否实现了接口u。<br>
AssignableTo(u Type)方法：用于判断是否可以赋值给类型u。就是是否可以用等号（=）来赋值。<br>
ConvertibleTo(u Type)方法：用于判断是否可以转换给类型u。就是是否可以进行类型转换。<br>
Comparable()方法：用于判断该类型是否是可比较的。就是是否可以用关系运算符进行比较。  </p>
<h4 id="shi-fou-shi-xian-le-mou-jie-kou"><a class="toclink" href="#shi-fou-shi-xian-le-mou-jie-kou">是否实现了某接口</a></h4>
<p>定义一个结构体，用Implements方法判断是否实现了指定的接口：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">person</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Age</span><span class="w">  </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">p</span><span class="w"> </span><span class="nx">person</span><span class="p">)</span><span class="w"> </span><span class="nx">String</span><span class="p">()</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">&quot;Name: %s, Age: %d&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">Name</span><span class="p">,</span><span class="w"> </span><span class="nx">p</span><span class="p">.</span><span class="nx">Age</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">p</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">person</span><span class="p">{</span><span class="s">&quot;Tom&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">pt</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span><span class="w"></span>

<span class="w">    </span><span class="nx">stringerType</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">((</span><span class="o">*</span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Stringer</span><span class="p">)(</span><span class="kc">nil</span><span class="p">)).</span><span class="nx">Elem</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;是否实现了fmt.Stringer接口：&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">pt</span><span class="p">.</span><span class="nx">Implements</span><span class="p">(</span><span class="nx">stringerType</span><span class="p">))</span><span class="w"> </span><span class="c1">// true</span><span class="w"></span>
<span class="w">    </span><span class="nx">writerType</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">((</span><span class="o">*</span><span class="nx">io</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)(</span><span class="kc">nil</span><span class="p">)).</span><span class="nx">Elem</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;是否实现了fmt.Writer接口:&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">pt</span><span class="p">.</span><span class="nx">Implements</span><span class="p">(</span><span class="nx">writerType</span><span class="p">))</span><span class="w">      </span><span class="c1">// false</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p><strong>注意：</strong>尽可能使用类型断言，而不是反射来判断接口是否实现了。这里是演示方法的使用。  </p>
<h3 id="shi-yong-fan-she"><a class="toclink" href="#shi-yong-fan-she">使用反射</a></h3>
<p>这一章节是更多reflect.Type和reflect.Value方法的使用。这里用了<strong>方法</strong>，但要知道reflect.Type是接口，而reflect.Value是结构体，这两者都有方法。<br>
类似python的getarrt、setattr，还有获取到方法后调用方法。大概有下面这些场景：</p>
<ul>
<li>遍历字段</li>
<li>遍历方法</li>
<li>获取字段，判断字段是否存在，修改字段值</li>
<li>获取方法，判断方法是否存在，调用方法</li>
</ul>
<p>下面的示例使用下面的结构体，定义了几个字段，分别定义了一个值方法和一个指针方法：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">student</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w">   </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Number</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">Height</span><span class="w"> </span><span class="kt">uint</span><span class="w"></span>
<span class="w">    </span><span class="nx">Weight</span><span class="w"> </span><span class="kt">float64</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="nx">student</span><span class="p">)</span><span class="w"> </span><span class="nx">Info</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;Name:\t%s\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">Name</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;Number:\t%03d\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">Number</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;Height:\t%d cm\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">Height</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;Weight:\t%.2f kg\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">.</span><span class="nx">Weight</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">student</span><span class="p">)</span><span class="w"> </span><span class="nx">SetHeightWeight</span><span class="p">(</span><span class="nx">h</span><span class="w"> </span><span class="kt">uint</span><span class="p">,</span><span class="w"> </span><span class="nx">w</span><span class="w"> </span><span class="kt">float64</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s</span><span class="p">.</span><span class="nx">Height</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">h</span><span class="w"></span>
<span class="w">    </span><span class="nx">s</span><span class="p">.</span><span class="nx">Weight</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">w</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="p">.</span><span class="nx">Info</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="p">.</span><span class="nx">SetHeightWeight</span><span class="p">(</span><span class="mi">172</span><span class="p">,</span><span class="w"> </span><span class="mf">65.9</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="p">.</span><span class="nx">Info</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="bian-li-zi-duan"><a class="toclink" href="#bian-li-zi-duan">遍历字段</a></h4>
<p>下面是遍历结构体字段的示例：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段属性</span><span class="w"></span>
<span class="w">    </span><span class="nx">st1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">NumField</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;字段属性：&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Name</span><span class="p">,</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Type</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段的值</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">NumField</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;字段值: &quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="nx">s2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Mary&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">160</span><span class="p">,</span><span class="w"> </span><span class="mf">45.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">st2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">s2</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">)</span><span class="w">  </span><span class="c1">// 这里传了指针</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段的属性和值</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">NumField</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">v</span><span class="p">:</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sv2</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="w">  </span><span class="c1">// 这里如果不取指针的值，会Panic</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%v(%v): %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Name</span><span class="p">,</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">Field</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Type</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* 输出结果：</span>
<span class="cm">字段属性： Name string</span>
<span class="cm">字段属性： Number int</span>
<span class="cm">字段属性： Height uint</span>
<span class="cm">字段属性： Weight float64</span>
<span class="cm">字段值:  Jimmy</span>
<span class="cm">字段值:  1</span>
<span class="cm">字段值:  170</span>
<span class="cm">字段值:  65.5</span>
<span class="cm">Name(string): Mary</span>
<span class="cm">Number(int): 2</span>
<span class="cm">Height(uint): 160</span>
<span class="cm">Weight(float64): 45.5</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>虽然这里没必要，不过有的时候是需要传指针的。上面例子中第二个实例就传了指针，之后在调用的时候，需要先调用Elem方法获取到指针指向的值。  </p>
<h4 id="bian-li-fang-fa"><a class="toclink" href="#bian-li-fang-fa">遍历方法</a></h4>
<p>遍历方法和遍历字段类似，不过方法有值接收者和指针接收者的问题，这里再仔细确认一下。<br>
主要差别就是把调用的方法名NumField、Field改为NumMethod、Method。然后再仔细比较下传值和传指针的区别：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段属性</span><span class="w"></span>
<span class="w">    </span><span class="nx">st1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">NumMethod</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;方法名：&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Name</span><span class="p">,</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Type</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段的值</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">NumMethod</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;方法值: &quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="nx">s2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Mary&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">160</span><span class="p">,</span><span class="w"> </span><span class="mf">45.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">st2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">)</span><span class="w"> </span><span class="c1">// 这里传了指针</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 遍历字段的属性和值</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">NumMethod</span><span class="p">();</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%v(%v): %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Name</span><span class="p">,</span><span class="w"> </span><span class="nx">st2</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">Type</span><span class="p">,</span><span class="w"> </span><span class="nx">sv2</span><span class="p">.</span><span class="nx">Method</span><span class="p">(</span><span class="nx">i</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* 输出结果：</span>
<span class="cm">方法属性： Info func(main.student)</span>
<span class="cm">方法值:  0x5cff60</span>
<span class="cm">Info(func(*main.student)): 0x5cff60</span>
<span class="cm">SetHeightWeight(func(*main.student, uint, float64)): 0x5cff60</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>第二个实例直接传指针，并且之后继续使用指针。此时可以遍历到值接收者的方法和指针接收者的方法。<br>
这里打印方法的值，应该是打印了方法的内存地址。之后会讲如何调用方法。  </p>
<h4 id="huo-qu-zi-duan"><a class="toclink" href="#huo-qu-zi-duan">获取字段</a></h4>
<p>上面使用遍历来获取字段和方法，也可以提供名称来指定获取。提供名称还会有指定的名称不存在的情况：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">st1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">n1</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">FieldByName</span><span class="p">(</span><span class="s">&quot;Height&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%#v, %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">n1</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">n2</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">FieldByName</span><span class="p">(</span><span class="s">&quot;School&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">n2</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">FieldByName</span><span class="p">(</span><span class="s">&quot;Height&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">FieldByName</span><span class="p">(</span><span class="s">&quot;School&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">.</span><span class="nx">String</span><span class="p">())</span><span class="w">  </span><span class="c1">// 虽然reflect.Value实现了String方法，但是可能优先调用了具体类型的String方法</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">.</span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Invalid</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* 输出结果：</span>
<span class="cm">reflect.StructField{Name:&quot;Height&quot;, PkgPath:&quot;&quot;, Type:(*reflect.rtype)(0x596320), Tag:&quot;&quot;, Offset:0x18, Index:[]int{2}, Anonymous:false}, true</span>
<span class="cm">{  &lt;nil&gt;  0 [] false} false</span>
<span class="cm">170</span>
<span class="cm">&lt;invalid reflect.Value&gt;</span>
<span class="cm">&lt;invalid Value&gt;</span>
<span class="cm">true</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>字段属性相关的信息，要通过reflect.Type获取。方法有两个返回值，第二个bool值用于判断字段是否存在。<br>
字段值则通过reflect.Value获取。这里只有一个返回值了，如果名称不存在会返回一个<code>reflect.Invalid</code>，用<code>v.Kind() == reflect.Invalid</code>来判断。这个判断逻辑和源码一致：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">v</span><span class="w"> </span><span class="nx">Value</span><span class="p">)</span><span class="w"> </span><span class="nx">String</span><span class="p">()</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">switch</span><span class="w"> </span><span class="nx">k</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">kind</span><span class="p">();</span><span class="w"> </span><span class="nx">k</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">Invalid</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="s">&quot;&lt;invalid Value&gt;&quot;</span><span class="w"></span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="nx">String</span><span class="p">:</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="kt">string</span><span class="p">)(</span><span class="nx">v</span><span class="p">.</span><span class="nx">ptr</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="s">&quot;&lt;&quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">v</span><span class="p">.</span><span class="nx">Type</span><span class="p">().</span><span class="nx">String</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot; Value&gt;&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>设置值的方法最开始已经讲过了，先获取到reflect.Value类型然后设置值。使用FieldByName和遍历时使用的Field方法一样是返回reflect.Value类型。之后的操作都一样，下面只给出一个简单的例子：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">svp1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">svp1</span><span class="p">.</span><span class="nx">Elem</span><span class="p">().</span><span class="nx">FieldByName</span><span class="p">(</span><span class="s">&quot;Height&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v</span><span class="p">.</span><span class="nx">SetUint</span><span class="p">(</span><span class="mi">172</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>修改值需要传指针，设置值的时候需要先调用Elem方法获取指针指向的值。  </p>
<h4 id="huo-qu-fang-fa"><a class="toclink" href="#huo-qu-fang-fa">获取方法</a></h4>
<p>获取方法和获取字段基本差不多，指针类型的方法的获取就不重复了：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">st1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">TypeOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">n1</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;Info&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%#v, %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">n1</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">n2</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">st1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;SetHeightWeight&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">n2</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sv1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;Info&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">v2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sv1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;SetHeightWeight&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">.</span><span class="nx">String</span><span class="p">())</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v2</span><span class="p">.</span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Invalid</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="cm">/* 输出结果：</span>
<span class="cm">reflect.Method{Name:&quot;Info&quot;, PkgPath:&quot;&quot;, Type:(*reflect.rtype)(0xc00004a060), Func:reflect.Value{typ:(*reflect.rtype)(0xc00004a060), ptr:(unsafe.Pointer)(0xc000006040), flag:0x13}, Index:0}, true</span>
<span class="cm">{  &lt;nil&gt; &lt;invalid Value&gt; 0} false</span>
<span class="cm">0x85ff60</span>
<span class="cm">&lt;invalid reflect.Value&gt;</span>
<span class="cm">&lt;invalid Value&gt;</span>
<span class="cm">true</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<h4 id="diao-yong-fang-fa"><a class="toclink" href="#diao-yong-fang-fa">调用方法</a></h4>
<p>之前的示例，获取到方法的值后，直接打印，看到的都是内存地址。获取到方法值后，一般的目的是为了调用。<br>
调用方法需要调用reflect.Type类型的Call方法，并且要提供参数。Call方法的参数是一个reflect.Value的切片，返回值也是一个reflect.Value的切片。无论是否有参数都要为Call方法传参，如果没有参数，就传空切片，传nil也是可以的。<br>
下面的示例调用了指针接收者的两个方法，一个有参数，一个没有参数：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">student</span><span class="p">{</span><span class="s">&quot;Jimmy&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">170</span><span class="p">,</span><span class="w"> </span><span class="mf">65.5</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">stp1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">f1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">stp1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;SetHeightWeight&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">f1</span><span class="p">.</span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Invalid</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Value</span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="nb">uint</span><span class="p">(</span><span class="mi">172</span><span class="p">)),</span><span class="w">  </span><span class="c1">// 直接填数值，会被认作是int类型，需要转成uint</span><span class="w"></span>
<span class="w">            </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">ValueOf</span><span class="p">(</span><span class="mf">66.6</span><span class="p">),</span><span class="w">       </span><span class="c1">// 浮点数不用转，默认就认作浮点数</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="nx">f1</span><span class="p">.</span><span class="nx">Call</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">f2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">stp1</span><span class="p">.</span><span class="nx">MethodByName</span><span class="p">(</span><span class="s">&quot;Info&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">f2</span><span class="p">.</span><span class="nx">Kind</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">reflect</span><span class="p">.</span><span class="nx">Invalid</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">f2</span><span class="p">.</span><span class="nx">Call</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span><span class="w">  </span><span class="c1">// 也可以传一个空切片 []reflect.Value{}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这里调用方法前加了判断，仅在方法名存在的时候才会调用。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>